package com.gitee.wsl.ext.string

import com.gitee.wsl.ext.number.pow

fun String.isRegexMatch(regex: Regex):Boolean = regex.matches(this)

/**
 * find the key code start positions and end positions
 * especially for code syntax
 *
 * @param KEY_CODE the key code
 * @return the list contains start positions and end positions for key code
 */
fun String.find(KEY_CODE: String): List<Pair<Int, Int>> {
    val text=this
    val list: MutableList<Pair<Int, Int>> = ArrayList()
    val lines = text.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
    var start = -1
    var end = -1
    var currentLength = 0
    for (i in lines.indices) {
        if (lines[i].startsWith(KEY_CODE)) {
            if (start == -1) {
                start = currentLength
            } else if (end == -1 && lines[i] == KEY_CODE) {
                end = currentLength
            }
            if (start != -1 && end != -1) {
                list.add(Pair(start, end))
                start = -1
                end = -1
            }
        }
        currentLength += lines[i].length + "\n".length
    }
    return list
}

//fun String.indexOfOrNull(char: Char, startIndex: Int = 0): Int? = this.indexOf(char, startIndex).takeIf { it >= 0 }

//fun String.lastIndexOfOrNull(char: Char, startIndex: Int = lastIndex): Int? =
//    this.lastIndexOf(char, startIndex).takeIf { it >= 0 }

fun String.indexOfInRange(char:Char, startIndex:Int, endIndex:Int):Int {

    for(i in startIndex until endIndex){
        if (this[i] == char)
            return i
    }
    return -1
}

/**
 * Finds next case sensitive character.
 * Case sensitive character is either lower-case or upper-case character.
 *
 * @param startIndex start search from index.
 * @return index of next case sensitive character or `empty` if no such character present
 */
fun CharSequence.indexOfNextCaseSensitiveCharacter(startIndex: Int): Int? {
    for (i in startIndex until length) {
        val c = this[i]
        if (c.isLowerCase() || c.isUpperCase()) {
            return i
        }
    }
    return null
}

/**
 * Count number of variation of words in case insensitive manner.
 * For example for word "a" - there are 2 variation ("a" and "A").
 * For word "1a" - there are also 2 variations ("1a" and "1A")
 * For word "AB" - there are 4 variations: ("ab", "aB", "Ab", "BB")
 *
 * @param value word to calculate variations
 * @return number of variations.
 */

fun String.countCaseInsensitiveVariations(): Long {

    val switchableCase = map { c -> if (c.isUpperCase() || c.isLowerCase()) 1 else 0 }.sum()

    return 2L.pow(switchableCase)
}

fun String.properLength() = map { if (it.code < 128) 1 else 2 }.sum()

fun String.getCommentStartIndex(allowEscapedQuotesInLiteralStrings: Boolean): Int {
    val isEscapingDisabled = if (allowEscapedQuotesInLiteralStrings) {
        // escaping is disabled when the config option is true AND we have a literal string
        val firstQuoteLetter = this.firstOrNull { it == '\"' || it == '\'' }
        firstQuoteLetter == '\''
    } else {
        false
    }

    val chars = if (!isEscapingDisabled) {
        this.replace("\\\"", "__")
            .replace("\\\'", "__")
    } else {
        this
    }.toCharArray()
    var currentQuoteChar: Char? = null

    chars.forEachIndexed { idx, symbol ->
        // take hash index if it's not enclosed in quotation marks
        if (symbol == '#' && currentQuoteChar == null) {
            return idx
        }

        if (symbol == '\"' || symbol == '\'') {
            if (currentQuoteChar == null) {
                currentQuoteChar = symbol
            } else if (currentQuoteChar == symbol) {
                currentQuoteChar = null
            }
        }
    }

    return -1
}

/**
 * @param substring
 * @return count of occurrences of substring in string
 */
fun String.getCountOfOccurrencesOfSubstring(substring: String): Int = this.split(substring).size - 1


fun String.substringBetween(delimiter:String) = substringAfter(delimiter,"").substringBefore(delimiter,"")

fun String.search(pattern: Regex): List<IntRange> {
    return pattern.findAll(this).map { it.range}.toList()
    //return pattern.find(this)?.groups?.map { it?.range }?:emptyList()
}

/**
 * Finds all indices of [char] in this CharSequence
 */
fun CharSequence.indicesOf(char: Char, ignoreCase: Boolean = false): List<Int> {
    val indices = mutableListOf<Int>()
    var index = -1

    do {
        index = this.indexOf(char, index + 1, ignoreCase)

        if (index > -1) {
            indices.add(index)
        }
    } while (index > -1)

    return indices
}

